package rpc

import (
	"fmt"
	"github.com/hashicorp/consul/api"
	"github.com/nacos-group/nacos-sdk-go/inner/uuid"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"
	common "user_service/config"
	"user_service/global"
	"user_service/handler"
	mlMongo "user_service/mongo"
	userProto "user_service/proto"
	"user_service/repository"
	"user_service/utils"
)

// RegisterService 注册服务
func RegisterService(db mlMongo.Database) {
	// 用户微服务IP
	serviceHost, err := utils.GetOutboundIP()
	if err != nil {
		zap.S().Errorw("获取容器IP失败", "err", err.Error())
		return
	}
	// 用户微服务端口
	servicePort := 6789
	// 用户微服务名称
	serviceName := common.Configs.Server.ServiceName
	zap.S().Infof("获取 容器IP：%s ; 系统端口 %d", serviceHost, servicePort)
	server := grpc.NewServer()
	// 初始化 UserServer
	userProto.RegisterUserServer(server, &handler.UserServer{
		// 设置超时
		ContextTimeout: time.Duration(1) * time.Second,
		// 初始化 userRepository
		UserRepository:    repository.NewUserRepository(db),
		CounterRepository: repository.NewCounterRepository(db),
	})
	// 初始化用户微服务的IP+端口监听器
	listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", serviceHost, servicePort))
	if err != nil {
		zap.S().Errorw("net.Listen错误", "err", err.Error())
		return
	}

	// 服务注册，连接consul。务必使用consul独立的服务发现配置
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("%s:%d", common.Configs.Consul.Discovery.Host, common.Configs.Consul.Discovery.Port)
	cfg.Token = common.Configs.Consul.Discovery.ACLToken
	global.Client, err = api.NewClient(cfg)

	if err != nil {
		zap.S().Errorw("服务注册 NewClient失败", "err", err.Error())
		return
	}

	// 生成检查对象
	check := &api.AgentServiceCheck{
		GRPC:                           fmt.Sprintf("%s:%d", serviceHost, servicePort),
		GRPCUseTLS:                     false,
		Timeout:                        "5s",
		Interval:                       "5s",
		DeregisterCriticalServiceAfter: "30s",
	}
	// 生成注册对象
	registration := new(api.AgentServiceRegistration)
	v4, err := uuid.NewV4()
	if err != nil {
		zap.S().Errorw("uuid.NewV4 failed", "err", err.Error())
		return
	}
	// 根据服务名称，生成UUID
	serviceID := v4.String()
	global.ServiceID = serviceID
	registration.ID = serviceID
	registration.Port = servicePort
	registration.Address = serviceHost
	registration.Name = serviceName
	registration.Tags = []string{"grpc", "user"} // 标签
	registration.Check = check
	err = global.Client.Agent().ServiceRegister(registration)

	if err != nil {
		zap.S().Errorw("Error", "message", "client.Agent().ServiceRegister 错误", "err", err.Error())
		return
	}
	zap.S().Infow("服务注册成功", "port", registration.Port, "ID", global.ServiceID)

	// 健康检查
	grpc_health_v1.RegisterHealthServer(server, health.NewServer())
	go func() {
		err = server.Serve(listen)
		panic(err)
	}()

	// 优雅关机
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	err = global.Client.Agent().ServiceDeregister(global.ServiceID)
	if err != nil {
		zap.S().Errorw("global.Client.Agent().ServiceDeregister 失败", "err", err.Error())
		return
	}
	zap.S().Infow("服务注销程", "serviceID", global.ServiceID)
}
